package com.xmall.search.service.impl.other;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch.core.*;
import co.elastic.clients.elasticsearch.core.bulk.BulkResponseItem;
import co.elastic.clients.elasticsearch.indices.CreateIndexRequest;
import co.elastic.clients.elasticsearch.indices.PutMappingRequest;
import com.xmall.define.base.BasePageQueryRequest;
import com.xmall.define.base.ResultCode;
import com.xmall.define.dto.es.EsBaseDto;
import com.xmall.exception.XmallException;
import com.xmall.search.define.callback.*;
import com.xmall.search.service.other.IElasticSearchService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ElasticSearchServiceImpl implements IElasticSearchService {

    @Resource
    private ElasticsearchClient client;

    /**
     * 创建索引
     */
    private void createIndex(String index) {
        try {
            ExistsRequest request = new ExistsRequest.Builder().index(index).build();
            if(!client.exists(request).value()) {
                CreateIndexRequest createIndexRequest = new CreateIndexRequest.Builder().index(index).build();
                client.indices().create(createIndexRequest);
            }
        }catch (Exception e){
            log.error("EsService createIndex: {}, error: {}", index, e.getMessage());
            throw new XmallException(ResultCode.SEARCH_CREATE_INDEX_ERROR);
        }
    }

    /**
     * 更新索引映射
     */
    @Override
    public void updateMapping(String index, PutMappingBuilderCallback callback) {
        try {
//            this.createIndex(index);

            PutMappingRequest.Builder putRequest = new PutMappingRequest.Builder().index(index);
            callback.build(putRequest);
            client.indices().putMapping(putRequest.build());
        }catch (Exception e){
            log.error("EsService updateMapping: {}, error: {}", index, e.getMessage());
            throw new XmallException(ResultCode.SEARCH_UPDATE_MAPPING_ERROR);
        }
    }

    /**
     * 批量保存
     */
    @Override
    public List<Long> save(String index, List<? extends EsBaseDto> requestList) {
        List<Long> successIdList = new ArrayList<>();
        successIdList.addAll(requestList.stream().map(EsBaseDto::getId).collect(Collectors.toList()));

        try {
            BulkRequest.Builder bulkRequest = new BulkRequest.Builder();
            requestList.forEach(request ->
                    bulkRequest.operations(op -> op.index(idx ->
                            idx.index(index)
                                    .id(request.getId().toString())
                                    .document(request)
                    ))
            );

            BulkResponse result = client.bulk(bulkRequest.build());
            List<Long> errorIdList = new ArrayList<>();
            if (result.errors()) {
                for (BulkResponseItem item: result.items()) {
                    if (item.error() != null) {
                        errorIdList.add(Long.valueOf(item.id()));
                    }
                }
            }

            return successIdList.stream().filter(successId ->
                    errorIdList.stream().noneMatch(errorId -> errorId.compareTo(successId) == 0))
                    .collect(Collectors.toList());
        }catch (Exception e) {
            log.error("EsService saveList: {}, error: {}", index, e.getMessage());
        }
        return successIdList;
    }

    /**
     * 删除
     */
    @Override
    public void delete(String index, DeleteRequestBuilderCallback callback) {
        try {
            DeleteByQueryRequest.Builder builder = new DeleteByQueryRequest.Builder().index(index);
            callback.build(builder);
            client.deleteByQuery(builder.build());
        }catch (Exception e) {
            log.error("EsService delete: {}, error: {}", index, e.getMessage());
            throw new XmallException(ResultCode.SEARCH_DELETE_ERROR);
        }
    }

    /**
     * 总数
     */
    @Override
    public Long count(String index, BasePageQueryRequest request, CountRequestBuilderCallback requestCallback) {
        try {
            CountRequest.Builder builder = new CountRequest.Builder().index(index);
            requestCallback.build(builder);
            return client.count(builder.build()).count();
        }catch (Exception e) {
            log.error("EsService count: {}, error: {}", index, e.getMessage());
        }
        return null;
    }

    /**
     * 分页列表
     */
    @Override
    public void listPage(String index, BasePageQueryRequest request, SearchRequestBuilderCallback requestCallback, ResponseCallback responseExtract, Class cls) {
        try {
            SearchRequest.Builder builder = new SearchRequest.Builder().index(index);
            requestCallback.build(builder);
            responseExtract.extract(client.search(builder.build(), cls));
        }catch (Exception e) {
            log.error("EsService listPage: {}, error: {}", index, e.getMessage());
        }
    }

}
